﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace ResourceEditor
{
    public partial class Form1 : Form
    {
        List<ResourceEntry> entries = new List<ResourceEntry>();
        Palette palette;

        string caption = "Dune 2000 Resource Editor";

        public Form1()
        {
            InitializeComponent();
            this.Text = caption;
        }

        private void openButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Filter = "Dune 2000 image resources (*.r8; *.r16)|*.r8;*.r16";

            if (openDialog.ShowDialog() == DialogResult.OK)
            {
                //LoadResourceFile(@"C:\Users\UserName\Documents\Dune\Working Directory\Data\DATA.R16");//openDialog.FileName);
                LoadResourceFile(openDialog.FileName);
            }
        }

        private void LoadResourceFile(string filename)
        {
            ////if (Path.GetExtension(filename).ToUpper() == ".R8")
            //{
            //    OpenFileDialog openDialog = new OpenFileDialog();
            //    openDialog.FileName = "PALETTE.BIN";
            //    openDialog.Filter = "Dune 2000 palette files (*.bin)|*.bin";

            //    if (openDialog.ShowDialog() == DialogResult.OK)
            //    {
            //        palette = new Palette(openDialog.FileName);
            //    }
            //    else
            //    {
            //        return;
            //    }
            //}
            this.Text = Path.GetFileName(filename) + " - " + caption;

            palette = new Palette(@"C:\Users\UserName\Documents\Dune\Working Directory\Data\Bin\PALETTE.BIN");

            entries.Clear();
            entryListBox.Items.Clear();
            FileStream fs = new FileStream(filename, FileMode.Open);
            BinaryReader br = new BinaryReader(fs);
            while (entries.Count < 8000 && fs.Position < fs.Length - 1)
            {
                ReadEntry(br);
            }
            br.Close();
            fs.Close();
            toolStripStatusLabel5.Text = "Entry Count: " + entries.Count.ToString();
            UpdateEntryPreview(0);
            for (int i = 0; i < entries.Count; i++)
            {
                entryListBox.Items.Add(string.Format("{0}{1}\t{2}x{3}", (entries[i].paletteHandle==0)?"":"P", i + 1, entries[i].width, entries[i].height));
            }
        }
        private void ReadEntry(BinaryReader br)
        {           
            CustomPalette customPalette = null;
            ResourceEntry entry = new ResourceEntry();
            byte firstValueTry = br.ReadByte();
            while (firstValueTry == 0)
            {
                firstValueTry = br.ReadByte();
            }
            entry.firstValue = firstValueTry;
            entry.width = br.ReadInt32();
            entry.height = br.ReadInt32();
            entry.xOffset = br.ReadInt32();
            entry.yOffset = br.ReadInt32();
            entry.imageHandle = br.ReadInt32();
            entry.paletteHandle = br.ReadInt32();
            entry.bitsPerPixel = br.ReadByte();
            entry.frameHeight = br.ReadByte();
            entry.frameWidth = br.ReadByte();
            entry.alignment = br.ReadByte();
            entry.imageData = new Color[entry.width, entry.height];

            // Custom Palette
            if (entry.firstValue == 1 && entry.paletteHandle != 0)
            {
                byte[,] imageData = new byte[entry.width, entry.height];

                customPalette = new CustomPalette();
                customPalette.Memory = br.ReadInt32();
                customPalette.PaletteHandle = br.ReadInt32();

                for (int y = 0; y < entry.height; y++)
                {
                    for (int x = 0; x < entry.width; x++)
                    {
                        imageData[x, y] = br.ReadByte();
                    }
                }

                for (int i = 0; i < 256; i++)
                {
                    customPalette.ColorPalette[i] = ConvertColor(br.ReadUInt16());
                }

                for (int y = 0; y < entry.height; y++)
                {
                    for (int x = 0; x < entry.width; x++)
                    {
                        entry.imageData[x, y] = customPalette.ColorPalette[imageData[x, y]];
                    }
                }
                entries.Add(entry);
            }
            else if (entry.firstValue == 2 && entry.paletteHandle != 0)
            {

                for (int y = 0; y < entry.height; y++)
                {
                    for (int x = 0; x < entry.width; x++)
                    {
                        br.ReadByte();
                        //entry.imageData[x, y] = customPalette.ColorPalette[br.ReadByte()];
                    }
                }
            }
            else // 16 bit colour or standard palette
            {
                for (int y = 0; y < entry.height; y++)
                {
                    for (int x = 0; x < entry.width; x++)
                    {
                        if (entry.bitsPerPixel == 16)
                            entry.imageData[x, y] = ConvertColor(br.ReadUInt16());
                        else
                            entry.imageData[x, y] = ConvertColor(br.ReadByte());
                    }
                }
                entries.Add(entry);
            }
            

        }
        /// <summary>
        /// Convert 15 bit (with 1 bit padding) colour to 24 bit
        /// </summary>
        /// <param name="colour"></param>
        /// <returns></returns>
        private Color ConvertColor(UInt16 colour)
        {
            //bits = XRRRRRGGGGGBBBBB
            byte red = (byte)((colour >> 10) & 0x1f);
            byte green = (byte)((colour >> 5) & 0x1f);
            byte blue = (byte)(colour & 0x1f);
            return Color.FromArgb(Convert.ToByte(255.0f * (float)red / 31), Convert.ToByte(255.0f * (float)green / 31), Convert.ToByte(255.0f * (float)blue / 31));
        }
        private Color ConvertColor(byte paletteIndex)
        {
            return palette.ColorPalette[paletteIndex];
        }

        private void entryListBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(entryListBox.SelectedIndex >= 0)
                UpdateEntryPreview(entryListBox.SelectedIndex);
        }
        private void UpdateEntryPreview(int entryIndex)
        {
            ResourceEntry selectedEntry = entries[entryIndex];
            Bitmap bitmap = new Bitmap(selectedEntry.width, selectedEntry.height);
            for (int x = 0; x < selectedEntry.width; x++)
            {
                for (int y = 0; y < selectedEntry.height; y++)
                {
                    bitmap.SetPixel(x, y, selectedEntry.imageData[x, y]);
                }
            }
            previewPictureBox.BackgroundImage = (Image)bitmap;

            firstValueTextBox.Text = selectedEntry.firstValue.ToString();
            widthTextBox.Text = selectedEntry.width.ToString();
            heightTextBox.Text = selectedEntry.height.ToString();
            xOffsetTextBox.Text = selectedEntry.xOffset.ToString();
            yOffsetTextBox.Text = selectedEntry.yOffset.ToString();
            imageHandleTextBox.Text = selectedEntry.imageHandle.ToString();
            paletteHandleTextBox.Text = selectedEntry.paletteHandle.ToString();
            bitsPerPixelTextBox.Text = selectedEntry.bitsPerPixel.ToString();
            frameHeightTextBox.Text = selectedEntry.frameHeight.ToString();
            frameWidthTextBox.Text = selectedEntry.frameWidth.ToString();
            alignmentTextBox.Text = selectedEntry.alignment.ToString();

        }

        private void zoomCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (zoomCheckBox.Checked)
                previewPictureBox.BackgroundImageLayout = ImageLayout.Zoom;
            else
                previewPictureBox.BackgroundImageLayout = ImageLayout.Center;
        }

        private void previewPictureBox_Paint(object sender, PaintEventArgs e)
        {
            if (entryListBox.SelectedIndex >= 0 && showFrameCheckBox.Checked)
            {
                ResourceEntry entry = entries[entryListBox.SelectedIndex];
                Graphics graphics = e.Graphics;
                Pen pen = new Pen(Color.Magenta);
                Point center = new Point(previewPictureBox.Size).Scale(0.5f);
                graphics.DrawRectangle(pen, new Rectangle(center.X - entry.frameWidth / 2, center.Y - entry.frameHeight / 2, entry.frameWidth, entry.frameHeight));
            }
        }

        private void showFrameCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            previewPictureBox.Refresh();
        }
    }
}
